package com.azzcs.spring.context;

import com.azzcs.spring.bean.AnnotatedBeanDefinition;
import com.azzcs.spring.bean.BeanDefinition;
import com.azzcs.spring.factory.BeanFactory;
import com.azzcs.spring.factory.DefaultListableBeanFactory;
import com.azzcs.spring.factory.config.AutowiredAnnotationBeanPostProcessor;
import com.azzcs.spring.factory.config.ConfigurationClassPostProcessor;
import com.azzcs.spring.factory.config.TransactionBeanPostProcessor;

/**
 * @Author: wzg
 * @Date: 2020/12/18 下午6:26
 */
public class ApplicationContext implements BeanFactory {

    private DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();

    public ApplicationContext(Class<?>... componentClasses) {
        register(componentClasses);
        refresh();
    }

    private void register(Class<?>... componentClasses) {
        for (Class<?> componentClass : componentClasses) {
            registerBean(componentClass);
        }
    }

    private void registerBean(Class<?> componentClass) {
        BeanDefinition beanDefinition = new AnnotatedBeanDefinition(componentClass);
        if (beanDefinition.isConfiguration()) {
            beanFactory.addBeanFactoryPostProcessor(new ConfigurationClassPostProcessor(beanDefinition));
        }
        if (beanDefinition.isBean()) {
            beanFactory.doRegisterBean(beanDefinition);
        }
        registerAutowiredAnnotationBeanPostProcessor();

    }

    private void registerTransactionBeanPostProcessor() {
        BeanDefinition beanDefinition = new AnnotatedBeanDefinition(TransactionBeanPostProcessor.class);
        beanFactory.doRegisterBean(beanDefinition);
        beanFactory.addBeanFactoryAware(getBean(beanDefinition.getBeanName()));
        beanFactory.addBeanBeanPostProcessor(getBean(beanDefinition.getBeanName()));
    }

    private void registerAutowiredAnnotationBeanPostProcessor() {
        BeanDefinition beanDefinition = new AnnotatedBeanDefinition(AutowiredAnnotationBeanPostProcessor.class);
        beanFactory.doRegisterBean(beanDefinition);
        beanFactory.addBeanFactoryAware(getBean(beanDefinition.getBeanName()));
        beanFactory.addBeanBeanPostProcessor(getBean(beanDefinition.getBeanName()));
    }

    public void refresh() {
        // 执行 spring 自己的 BeanFactoryPostProcessor
        invokeBeanFactoryPostProcessors(beanFactory);
        // 注册 BeanPostProcessors
        registerBeanPostProcessors(beanFactory);
        // 加载 Bean
        finishBeanFactoryInitialization(beanFactory);
    }

    private void finishBeanFactoryInitialization(DefaultListableBeanFactory beanFactory) {
        beanFactory.finishBeanFactoryInitialization();
    }

    private void registerBeanPostProcessors(DefaultListableBeanFactory beanFactory) {
        // 注册 事物管理器 BeanPostProcessor
        registerTransactionBeanPostProcessor();
        beanFactory.registerBeanPostProcessors();
    }

    private void invokeBeanFactoryPostProcessors(DefaultListableBeanFactory beanFactory) {
        beanFactory.invokeBeanFactoryPostProcessors();

    }

    @Override
    public Object getBean(String name) {
        return beanFactory.getBean(name);
    }

    @Override
    public <T> T getBean(Class<T> requiredType) {
        return beanFactory.getBean(requiredType);
    }

    @Override
    public boolean containsBean(String name) {
        return beanFactory.containsBean(name);
    }
}
